"""
# -*- coding: utf-8 -*-

Created on 2021/5/25 18:15

@File: examine_data.py
@Author: LT
@Description: 校验收到的excel表格格式，不符合格式要求，就应该立马驳回要求重改，并停止后续程序
            	序号（选填）
            	场站名字（必填）
            	用采系统户号（必填）
            	用采系统户名（必填）
            	经度（必填）
            	纬度（必填）
            	是否为小微园（必填）
            	省（必填）
            	市（必填）
            	地址（必填）
            	街道村镇（必填）
            	县域（必填）
            	供电区域（必填）
            	负责人（选填）
            	电话（选填）
            	网关厂家（必填）
"""
import os
from openpyxl import load_workbook
from ..common.read_settings import SettingsWrapper
from ..about_gui.gui_mainloop_demo import GuiDemo
# from True_Establishment_package.True_Establishment.common.read_settings import SettingsWrapper
# from True_Establishment_package.True_Establishment.about_gui.gui_mainloop_demo import GuiDemo

# from True_Establishment_package.True_Establishment.common.read_settings import SettingsWrapper    # 若不将 True_Establishment_package 之上的目录设置成源根，则会出错

# os.chdir(os.path.dirname(os.path.realpath(__file__)))       # 这里用了改变路径来替代了os.path.join的方法
excel_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "template.xlsx")       # 这里用了改变路径来替代了os.path.join的方法


##########################################
# 这里放置了各种问题的异常类，来反应各种不同的情况
##########################################
class NoTargetSheetException(Exception):
    """无目标sheet名异常"""
    pass


class WrongHeaderException(Exception):
    """工作表中的标题栏有增删改动！"""
    pass


class IllegalPunctuationException(Exception):
    """工作表中有非法的字符"""
    pass


class VoidValueException(Exception):
    """excel表格里必填表头下有空值内容"""
    pass


class DoorNameDoorNumRepeatingException(Exception):
    """excel表里户名、户号这两栏有无重复项"""
    pass


# 使用GUI界面来让用户输入对应的模板
# myexceldialog = GuiDemo()
# myexceldialog.mainloop()
# fetched_excel_path = myexceldialog.open_name


class Examination(SettingsWrapper):
    def __init__(self):
        SettingsWrapper.__init__(self)

        # self.wb = load_workbook('template.xlsx')
        self.wb = load_workbook(excel_path)
        # self.wb = load_workbook(fetched_excel_path)
        self.target_sheet_name = 'Sheet1'                   # 可根据具体情况实时修改，但目前固定为目标表名为Sheet1
        self.illegal_punctuation = ('#', '\n')              # 指定不能在excel中出现的非法字符
        self.check_res = self.format_checker(self.wb)       # 实例建立之初就去检查格式，并将检查结果返回；只有验证合格后，结果才为真。

    def format_checker(self, src_wb):
        try:
            self.__check_sheet_name()               # 检查有无名为Sheet1的表格，这个如果没有那就算是最高级别的错误，后续都不能进行展开
            self.__check_sheet_header()             # 检查表头（第一行）的关键字有无删减增加
            self.__check_sheet_content()            # 检查内容是否为空
            self.__check_sheet_repeating_item()     # 检查户名、户号这两栏有无重复项

        # 如果有不符合的地方则，则将 所有 错误写进日志
        except Exception as e:
            raise Exception(f'错误情况--> {e}')

        # 如果没有不符合的地方，可以什么都不返回；也可以返回一个标志告诉告诉接下来的extract_from_data可以提取数据了
        else:
            # 无事发生，说明表格验证合格
            return True

    def __check_sheet_name(self):
        if self.target_sheet_name not in self.wb.sheetnames:
            raise NoTargetSheetException(f'工作簿中没有名为 {self.target_sheet_name} 的目标工作表')

    def __check_sheet_header(self):
        work_sheet = self.wb[self.target_sheet_name]

        # iter_rows是按行迭代，每次返回代表实际表格中一个指定行的迭代器，以此逻辑做一个生成器
        def title_value_generator():
            for cell_tuple in work_sheet.iter_rows(min_row=1, max_col=work_sheet.max_column, max_row=1, values_only=True):
                for cell in cell_tuple:
                    yield cell

        if len(self.excel_titles_list) <= work_sheet.max_column:             # 当规定标题长度小于从实际表中获得的长度
            complements = set(title_value_generator()) - set(self.excel_titles_list)
            if len(complements) > 0:
                raise WrongHeaderException(f'目标工作表中的标题栏中不应该有：{complements}！')
        elif len(self.excel_titles_list) > work_sheet.max_column:           # 当规定标题长度大于从实际表中获得的长度
            complements = set(self.excel_titles_list) - set(title_value_generator())
            if len(complements) > 0:
                raise WrongHeaderException(f'目标工作表中的标题栏中缺少：{complements}！')

    def __check_sheet_content(self):
        """
        为了和联元数据库中贴近，内容除了必要项不能为空外，内容中任何地方也不能出现 '#' 以及换行符 '\n'
        优先级排序：
        1.不能有'#'符号 和 '\n'符号
        2.必要列的内容不能为空，何为必要列已经在配置文件中给出
        :return: None
        """
        work_sheet = self.wb[self.target_sheet_name]

        def illegal_punctuations_checker(illegal_punctuation=self.illegal_punctuation):
            """检查excel表格里是否有 '#', '\n'这样的非法标点符号"""
            for row in work_sheet.values:
                for value in row:
                    for each_punctuation in illegal_punctuation:
                        if each_punctuation in str(value):
                            raise IllegalPunctuationException(r"'excel表格里不能有 #, 换行符号 这样的非法标点符号！'")

        def none_value_checker():
            """检查必填项表头中是否有空值，思路是：通过关键字锁定列的min,max值，通过worksheet.iter_cols()来列迭代，看是否有None值"""

            # 需要有个操作来查出与必要表头符合的具体索引号所在！注意，索引号要+1才能正确表示openpyxl的位置！，这就需要与第一行表头的内容较劲
            title_range = [row for row in work_sheet.rows][0]                       # 获取excel表的标题范围
            title_list = [each.value for each in title_range]                       # 为了获取实际的标头索引，而非固定的索引，先获取标头列表
            indices_list = []
            for each_necessary_title in self.excel_none_value_forbidden_titles_list:
                for each_title in title_range:
                    if each_necessary_title == each_title.value:
                        indices_list.append((each_title.value, title_list.index(each_necessary_title) + 1))     # +1是为了契合openpyxl的行列索引+1
                        # indices_list.append((each_title.value, self.excel_titles_list.index(each_necessary_title) + 1))  已淘汰、弃用

            # print(indices_list)
            # 用找到的索引号，来使用列迭代，一旦查出此列中有None值，就引发异常
            for each_title in indices_list:     # indices_list里每个元素是个元组，
                for col in work_sheet.iter_cols(min_row=2,                          # 这个最小行必须为2，因为不能光有表头
                                                max_row=work_sheet.max_row,
                                                min_col=each_title[1], max_col=each_title[1]):
                    for cell in col:
                        # print(cell.value, f"now each_title name is {each_title[0]} index is {each_title[1]}")
                        if cell.value is None:
                            raise VoidValueException(f'标题：{each_title[0]} 下有空值！')

        illegal_punctuations_checker()
        none_value_checker()

    def __check_sheet_repeating_item(self):
        """采用的思路是：对指定列的内容使用集合，然后通过len函数判断长度是否与原始长度相等，若相等则无重复；否则有重复"""
        work_sheet = self.wb[self.target_sheet_name]

        # 用指定的不可有重复值表头列表来返回首行迭代器的index
        title_list = [each_title.value for each_title in [row for row in work_sheet.rows][0]]
        indices_list = []
        for each in self.excel_repeating_forbidden_titles_list:
            indices_list.append(title_list.index(each))

        # 根据这个index来返回对应的列迭代器
        target_columns = []
        for each_index in indices_list:
            target_columns.append([each_col.value for each_col in [col for col in work_sheet.columns][each_index]])

        # TODO: 用对应的列迭代器来进行集合len对比
        for each_columns in target_columns:
            if len(set(each_columns)) != len(each_columns):
                raise DoorNameDoorNumRepeatingException(f'{self.excel_repeating_forbidden_titles_list}表头下有重复值！')


if __name__ == '__main__':
    exp = Examination()
